import sys, socket, struct, urllib, time

class Client:
    
    def __init__(self, username=None, password=None):
        assert(username != None)
        assert(password != None)
        assert(username != '')
        assert(password != '')
        
        self.username = username
        self.password = password
        self.start_time = time.time()
        self.protocol_version = 29
        self.buffer = ''

    def connect(self, host, port):
        # Get session from minecraft.net
        response = urllib.urlopen('http://www.minecraft.net/game/getversion.jsp?user=%s&password=%s&version=%d' % (self.username, self.password, self.protocol_version)).read()

        parts = []
        version = ''
        ticket = ''

        if response == 'Error' or response == 'Old version':
            self.log("minecraft.net: %s" % response)
            return False
        
        self.log("minecraft.net: %s" % response)
        parts = response.split(":")
        self.log(str(parts))
        version = parts[0]
        ticket = parts[1]
        self.sessionid = parts[3]

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((socket.gethostbyname(host), port))
        self.send_handshake()

        response = urllib.urlopen('http://www.minecraft.net/game/joinserver.jsp?user=%s&sessionId=%s&serverId=%s' % (self.username, self.sessionid, self.serverid))
        self.send_login()
        self.send_keep_alive()
        return True
        
    def run(self):
        while True:
            self.buffer = self.buffer + self.sock.recv(1024)
            sys.stdout.write(self.buffer)
        
    def idle(self, seconds):
        self.log('idle: %d seconds' % seconds)
        
        idle_start = time.time()
        while True:
            dt = time.time() - idle_start
            if dt > seconds:
                self.log('resuming')
                return

    def send_handshake(self):
        self.log('packet: handshake')
        
        # Send the handshake packet http://www.wiki.vg/minecraft/protocol#handshake
        packet = ''        
        packet += struct.pack('b', 0x02) # Packet type
        packet += struct.pack('!H', len(self.username)) # username length, unsigned int, network (big-endian) byte order
        packet += self.username
        self.sock.send(packet)
        
        # Recieve the server id
        self.sock.recv(4096)
        data = self.sock.recv(4096)
        pieces = [data[i:i+2] for i in range(0, len(data), 2)]
        pieces.pop(0)
        self.serverid = "".join(pieces)
        
        

    def send_login(self):
        self.log('packet: login')

        # Send the login packet http://www.wiki.vg/minecraft/protocol#login
        packet = ''
        packet += struct.pack('b', 0x01) # Packet type
        packet += struct.pack('>i', 2) # Protocol version number
        packet += struct.pack('!H', len(self.username)) ## username length, unsigned int, network (big-endian) byte order
        packet += self.username
        packet += struct.pack('!H', len(self.password)) ## password length, unsigned int, network (big-endian) byte order
        packet += self.password
        self.sock.send(packet)

    def send_keep_alive(self):
        self.log('packet: keep_alive')

        # Send the keep_alive packet http://www.wiki.vg/minecraft/protocol#keep_alive
        packet = struct.pack('b', 0x00)
        self.sock.send(packet)
    
    def chat(self, message):
        self.log('packet chat: %s' % message)
        packet = ''
        packet += struct.pack('b', 0x03) # Packet type
        packet += struct.pack('!H', len(message))
        packet += message
        self.sock.send(packet)
    
    def log(self, message):
        sys.stdout.write("%s \n" % message)
        sys.stdout.flush()

if __name__ == "__main__":
    Client('SeR', 1234)
